mergeConcatSwitchExhaustMap
rxjs: mergeMap, switchMap, concatMap, exhaustMap
Problem
Imagine you have to get a list of articles, and when you click on an article you need to get all the comments for that article.
The naive approve will be to do that:
fetcMyArticle().pipe(
map(article => {
return fetchComments(article.id);
})
)
But this will not work, because the fetchComments
will return an observable, and the map
operator will return an observable of observables (higher order observables).
Solution
The solution is to use the mergeMap
operator, which will subscribe to the inner observable and emit its values.
fetcMyArticle().pipe(
mergeMap(article => {
return fetchComments(article.id);
})
)
This will work, but why ?
mergeMap vs switchMap vs concatMap vs exhaustMap
First of all, all of theses operators are composed of two operators, the map
operator and the merge
, switch
, concat
or exhaust
operator.
mergeMap: map + mergeAll switchMap: map + switchAll concatMap: map + concatAll exhaustMap: map + exhaustAll
So in our example:
fetcMyArticle().pipe(
mergeMap(article => {
return fetchComments(article.id);
})
)
are equivalent to:
fetcMyArticle().pipe(
map(article => {
return fetchComments(article.id);
}),
mergeAll()
)
All of theses operators ending with All
will described the asynchrone behavior that you want to use. So you need to choose which user experience you want to provide to your users.
Dumb schema
Legend: 🍖: will take 30 minutes 🍺: will take 5 minutes 🍔: will take 10 minutes
{ 🍖, 🍺, 🍔 } ----- concatMap ----- [🍖, 🍺, 🍔]
{ 🍖, 🍺, 🍔 } ----- mergeMap ----- [🍺, 🍔, 🍖]
{ 🍖, 🍺, 🍔 } ----- switchMap ----- [🍔]
{ 🍖, 🍺, 🍔 } ----- exhaustMap ----- [🍖]
ConcatMap will serve the request in the same order as they come.
mergeMap will serve the request as soon as they are ready.
switchMap will cancel the previous request if a new one comes
exhaustMap will ignore the new request if a request is already in progress.
How ?
Questions to ask yourself to choose the right operator:
Am i on the view or the data access ? (view: [switchMap,exhaustMap], data access: [mergeMap,concatMap])
Data access: Do in need to keep the order ? (concatMap)
Data access: Faster but without order ? (mergeMap)
View: Minimize request cost ? (exhaustMap)
View: Cancel previous request, premium UX ? (switchMap)